package br.usp.ime.ingpos.services;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Set;

import javax.persistence.FetchType;

import org.hibernate.annotations.Fetch;
import org.hibernate.annotations.FetchMode;
import org.springframework.beans.BeanUtils;

import br.com.caelum.vraptor.ioc.Component;
import br.com.caelum.vraptor.ioc.RequestScoped;
import br.usp.ime.ingpos.modelo.Candidato;
import br.usp.ime.ingpos.modelo.Inscricao;
import br.usp.ime.ingpos.modelo.Orientador;
import br.usp.ime.ingpos.modelo.ProcessoSeletivo;
import br.usp.ime.ingpos.modelo.Usuario;
import br.usp.ime.ingpos.modelo.dao.InscricaoDAO;
import br.usp.ime.ingpos.modelo.dao.OrientadorDAO;
import br.usp.ime.ingpos.web.controllers.UsuarioSessao;

@RequestScoped
@Component
public class InscricaoService
{
    private final InscricaoDAO inscricaoDAO;
    private final UsuarioSessao usuarioSessao;
    private final UsuarioService usuarioService;
    private final CandidatoService candidatoService;
    private final ProcessoSeletivoService processoSeletivoService;
    private final OrientadorService orientadorService;

    public InscricaoService(
        final UsuarioSessao usuarioSessao,
        final UsuarioService usuarioService,
        final InscricaoDAO inscricaoDAO,
        final CandidatoService candidatoService,
        final ProcessoSeletivoService processoSeletivoService,
        final OrientadorService orientadorService
    )
    {
        this.usuarioSessao = usuarioSessao;
        this.usuarioService = usuarioService;
        this.inscricaoDAO = inscricaoDAO;
        this.candidatoService = candidatoService;
        this.processoSeletivoService = processoSeletivoService;
        this.orientadorService = orientadorService;
    }

    public void inserirOuAtualizarInscricao(
        final Inscricao inscricao )
    {
        Candidato candidato = candidatoService.getCandidatoAtual();
        Inscricao inscricaoAtual = getInscricaoAtual();
        if( inscricaoAtual == null ) {
            // Nova inscricao
            inscricao.setCandidato( candidato );
            inscricaoDAO.saveOrUpdate( inscricao );
            candidato.insereInscricao( inscricao );
            candidatoService.atualizar( candidato );
        } else {
            // Atualizacao de inscricao
            BeanUtils.copyProperties( inscricao, inscricaoAtual, new String[] {
                "inscricaoID"
            } );

            inscricaoDAO.saveOrUpdate( inscricaoAtual );
        }
    }

    public Inscricao procurarPorCandidatoEPorProcessoSeletivo(
        final Candidato candidato,
        final ProcessoSeletivo processoSeletivo )
    {
        return inscricaoDAO.procurarPorCandidatoEProcessoSeletivo( candidato, processoSeletivo );
    }

    public void removeInscricao(
        Inscricao inscricao )
    {
        inscricaoDAO.removeInscricao( inscricao );
    }

    public Inscricao getInscricaoAtual(
        Usuario usuario )
    {
        if( usuario == null )
            usuario = usuarioService.procurarPorId( usuarioSessao.getUsuario().getUsuarioID() );

        Candidato candidato = (Candidato) usuario;

        Set<Inscricao> inscricoes = candidato.getInscricoes();
        List<ProcessoSeletivo> processosSeletivos = processoSeletivoService.buscarProcessosSeletivosVigentes();

        for (Inscricao inscricao : inscricoes) {
            for( ProcessoSeletivo processoSeletivo : processosSeletivos ){
                if( inscricao.getProcessoSeletivo().equals( processoSeletivo) )
                    return inscricao;
            }
        }
        return null;
    }

    public Inscricao getInscricaoAtual()
    {
        return getInscricaoAtual( null );
    }

    public List<Inscricao> getCandidatosPorProcessoSeletivo(ProcessoSeletivo processoSeletivo){
        return inscricaoDAO.procurarProcessoSeletivo( processoSeletivo );

    }

    public List<Inscricao> getCandidatosAprovadosPorProcessoSeletivo(ProcessoSeletivo processoSeletivo){
        return inscricaoDAO.procurarPorCandidatosAprovadosNoProcesso(processoSeletivo);
    }

    public void copiaPropriedades(
        Inscricao destino,
        Inscricao origem )
    {
        destino.setAreasDeInteresseAfinidade1( origem.getAreasDeInteresseAfinidade1() );
        destino.setAreasDeInteresseAfinidade2( origem.getAreasDeInteresseAfinidade2() );
        destino.setAreasDeInteresseAfinidade3( origem.getAreasDeInteresseAfinidade3() );

        destino.setDedicacaoExclusiva( origem.getDedicacaoExclusiva() );
        destino.setExposicaoPropositos( origem.getExposicaoPropositos() );
        destino.setObservacoes( origem.getObservacoes() );
        destino.setOrientadorDesejado( origem.getOrientadorDesejado() );
        destino.setOutrosProcessosSeletivos( origem.getOutrosProcessosSeletivos() );
        destino.setProcessoSeletivo( origem.getProcessoSeletivo() );
        destino.setSabeAreasDeInteresse( origem.isSabeAreasDeInteresse() );
    }

    public void salvaAprovados(final List<String> aprovados, final List<String> reprovados){
        if(aprovados != null)
            for( String hash : aprovados ) {
                Usuario usuario = usuarioService.procurarPorHash( hash );
                Inscricao inscricao = getInscricaoAtual( usuario );
                inscricao.setAprovado( true );
                inscricaoDAO.saveOrUpdate( inscricao );
            }
        if(reprovados != null)
            for( String hash : reprovados ) {
                Usuario usuario = usuarioService.procurarPorHash( hash );
                Inscricao inscricao = getInscricaoAtual( usuario );
                inscricao.setAprovado( false );
                inscricaoDAO.saveOrUpdate( inscricao );
            }
    }

    public void salvaEntrevistados(
        List<String> entrevistados, List<String> naoConversaram )
    {
        if(entrevistados != null)
            for(String hash : entrevistados){
                Usuario usuario = usuarioService.procurarPorHash( hash );
                Inscricao inscricao = getInscricaoAtual( usuario );
                inscricao.setConversouComCoordenador( true );
                inscricaoDAO.saveOrUpdate( inscricao );
            }
        if(naoConversaram != null)
            for(String hash : naoConversaram){
                Usuario usuario = usuarioService.procurarPorHash( hash );
                Inscricao inscricao = getInscricaoAtual( usuario );
                inscricao.setConversouComCoordenador( false );
                inscricaoDAO.saveOrUpdate( inscricao );
            }
    }

    public List<Inscricao> getCandidatosReprovadosPorProcessoSeletivo(
        ProcessoSeletivo processoSeletivo )
        {
        return inscricaoDAO.procurarPorCandidatosReprovadosNoProcesso(processoSeletivo);
        }

    public String salvaOrientadores(List<Inscricao> inscricoes, List <String> orientadores) {
        StringBuilder orientadoresInvalidos = new StringBuilder();

        for (int i = 0; i < inscricoes.size(); i++) {
            Inscricao inscricao = inscricoes.get(i);
            String nomeOrientador = orientadores.get(i);
            Orientador orientador = null;

            if (nomeOrientador != null && nomeOrientador.length() != 0)
                orientador = orientadorService.procuraOrientadorPorNome(nomeOrientador);

            if (nomeOrientador != null && nomeOrientador.length() != 0 && orientador == null) /* Orientador nao existe */
                orientadoresInvalidos.append(nomeOrientador).append(", ");

            Inscricao inscricaoDeVerdade = inscricaoDAO.findById(inscricao.getInscricaoID());
            		
            Orientador orientadorAnterior = inscricaoDeVerdade.getOrientadorAtribuido();
            
			if (orientadorAnterior != null) {
				int quantidadeOrientandosAnterior = orientadorAnterior
						.getQuantidadeOrientandosAtribuidos();
				orientadorAnterior
						.setQuantidadeOrientandosAtribuidos(quantidadeOrientandosAnterior - 1);
				orientadorService.salvar(orientadorAnterior);
			}
			if (orientador != null) {
				int quantidadeOrientandosAnterior = orientador
						.getQuantidadeOrientandosAtribuidos();
				orientador
						.setQuantidadeOrientandosAtribuidos(quantidadeOrientandosAnterior + 1);
				orientadorService.salvar(orientador);
			}
            		
            inscricaoDeVerdade.setOrientadorAtribuido(orientador);
            inscricaoDAO.save(inscricaoDeVerdade);
            
        }

        int length = orientadoresInvalidos.length();		
        if (length != 0)
            orientadoresInvalidos.delete(length - 2, length);

        return orientadoresInvalidos.toString();
    }

    public boolean inscricaoFinalizada(){
        if(getInscricaoAtual( usuarioSessao.getUsuario() ) == null)
            return false;
        return true;
    }
	
    public void verificaInscricoes( List<Inscricao> listaDeInscricoes )
    {
        for( Inscricao inscricao : listaDeInscricoes ) {
            inscricao.setInscricaoFinalizada( inscricaoFinalizada( inscricao.getCandidato() ));
        }
    }
	
	
	public boolean inscricaoFinalizada(Candidato candidato){
	    if(getInscricaoAtual( candidato ) == null)
	        return false;
	    if(candidato.getCurriculo() == null)
	        return false;
	    if(candidato.getDadosPessoais() == null)
	        return false;	    
	    return true;
	}
}
